package com.shhm.filter;

import com.alibaba.fastjson2.JSON;
import com.github.benmanes.caffeine.cache.Cache;
import com.shhm.common.context.PermsContextHolder;
import com.shhm.common.entity.admin.SysRoleOperatePerms;
import com.shhm.common.entity.admin.SysUser;
import com.shhm.common.entity.system.SysPassAuth;
import com.shhm.common.utils.JwtUtil;
import com.shhm.common.utils.RedisUtil;
import com.shhm.common.utils.ResponseUtil;
import com.shhm.common.dto.security.SecurityUser;
import com.shhm.common.utils.SysPermsUtil;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.util.List;
import java.util.Objects;

/**
 * @author JackZ
 * @version 1.0
 * @description: TODO
 * @date 2025/7/25 下午3:00
 */
public class JwtAuthenticationFilter extends OncePerRequestFilter {
    private final String[] pass_uri;
    private final RedisTemplate<String, String> redisTemplate;
    private final Cache<String, List<SysPassAuth>> localSysPassAuthCache;
    private final PasswordEncoder passwordEncoder;
    @Value("${filter.openAuthentication}")
    private boolean openFilter;

    public JwtAuthenticationFilter(
            String[] pass_uri,
            RedisTemplate<String, String> redisTemplate,
            Cache<String, List<SysPassAuth>> localSysPassAuthCache,
            PasswordEncoder passwordEncoder
    ) {
        this.pass_uri = pass_uri;
        this.redisTemplate = redisTemplate;
        this.localSysPassAuthCache = localSysPassAuthCache;
        this.passwordEncoder = passwordEncoder;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
//        if (!openFilter){
//            filterChain.doFilter(request, response);
//            return;
//        }

        String uri = request.getRequestURI();
        for (String puri : pass_uri) {
            if (uri.contains(puri)){
                filterChain.doFilter(request, response);
                return;
            }
        }

        // 从Header提取Token
        String authHeader = request.getHeader("Authorization");
        if (authHeader == null || !authHeader.startsWith("Bearer ")) {
            ResponseUtil.sendErrorResponse(response,401,"认证异常！");
            return;
        }

        String token = authHeader.substring(7);
        String validation = JwtUtil.validateToken(token);


        if (!validation.equals("pass")){
            ResponseUtil.sendErrorResponse(response,401,validation);
            return;
        }

        Integer uid = JwtUtil.getUIDFromToken(token);
        List<String> roles = JwtUtil.getRoleFromToken(token);
        String tokenExpire = redisTemplate.opsForValue().get(RedisUtil.REDIS_BLACK_TOKEN_KEY + uid);

        if (Objects.nonNull(tokenExpire)){
            ResponseUtil.sendErrorResponse(response,401,"令牌已过期");
            return;
        }

        String userJsonString = redisTemplate.opsForValue().get(RedisUtil.REDIS_USER_ONLINE_KEY + uid);
        SysUser user = JSON.parseObject(userJsonString, SysUser.class);
        SecurityUser su = new SecurityUser();
        su.copySysUser(user);
        su.setRoles(roles);
        if (Objects.isNull( user)) {
            ResponseUtil.sendErrorResponse(response,401,"用户信息异常，请重新登录");
            return;
        }
        UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(su, user.getPassword(), su.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(auth);

        filterChain.doFilter(request, response);
    }
}
